

package com.project.framework.interceptor;

import java.io.PrintWriter;
import java.io.StringWriter;
import java.util.UUID;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import com.project.common.constant.LogConstants;
import com.project.common.utils.ServletUtils;
import com.project.common.utils.StringUtils;
import lombok.extern.slf4j.Slf4j;
import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.annotation.AfterReturning;
import org.aspectj.lang.annotation.AfterThrowing;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Before;
import org.aspectj.lang.annotation.Pointcut;
import org.slf4j.MDC;
import org.springframework.core.io.InputStreamSource;
import org.springframework.stereotype.Component;
import org.springframework.web.multipart.support.StandardMultipartHttpServletRequest;

import com.alibaba.fastjson.JSONObject;


@Slf4j
@Component
@Aspect
public class ControllerLogIntercept {


    private ThreadLocal<Long> threadLocal = new ThreadLocal<>();

    @Pointcut("execution(public * com.project.*.*.controller..*.*(..))")
    public void cutController() {

    }

    @Pointcut("@annotation(org.springframework.web.bind.annotation.RequestMapping)")
    public void cutRequestMapping() {

    }

    @Pointcut("@annotation(org.springframework.web.bind.annotation.GetMapping)")
    public void cutGetMapping() {
    }

    @Pointcut("@annotation(org.springframework.web.bind.annotation.PostMapping)")
    public void cutPostMapping() {
    }

    @Pointcut("cutController() || cutRequestMapping() || cutGetMapping() || cutPostMapping()") // 切入点表达式
    public void pointcut() {

    }

    @Before(value = "pointcut()")
    public void before(JoinPoint joinPoint) {
        if (StringUtils.isEmpty(MDC.get(LogConstants.TRACE_ID))) {
            MDC.put(LogConstants.TRACE_ID, UUID.randomUUID().toString().replace("-", ""));
        }
        // 获取执行的方法名称
        String className = joinPoint.getTarget().getClass().getSimpleName();
        String methodName = joinPoint.getSignature().getName();
        Object[] args = joinPoint.getArgs();
        StringBuilder params = new StringBuilder("参数====>" + className + "." + methodName + "=>");
        //获取请求参数集合并进行遍历拼接
        for (Object object : args) {
            if (object instanceof HttpServletRequest || object instanceof HttpServletResponse) {
                continue;
            }

            if (object instanceof InputStreamSource) {
                continue;
            }

            if (object instanceof StandardMultipartHttpServletRequest) {
                continue;
            }

            try {
                params.append(JSONObject.toJSONString(object) + ",");
            } catch (Exception e) {
                log.info("json化参数异常");
            }

        }
        HttpServletRequest request = ServletUtils.getRequest();
        params.append("{url:" + request.getRequestURI() + "}");
        params.append("{channelCode:" + request.getHeader("channelCode") + "}");
        params.append("{token:" + request.getHeader("token") + "}");

        threadLocal.set(System.currentTimeMillis());
        //打印请求参数参数
        log.info(params.toString());
    }

    @AfterReturning(pointcut = "pointcut()", returning = "returnValue")
    public void afterHandle(JoinPoint point, Object returnValue) {
        log.info("返回====>{}  耗时====>{}", JSONObject.toJSONString(returnValue), (System.currentTimeMillis() - threadLocal.get()) + "ms");
        threadLocal.remove();
        MDC.remove(LogConstants.TRACE_ID);
    }

    @AfterThrowing(pointcut = "pointcut()", throwing = "e")
    public void afterThrowable(JoinPoint joinPoint, Throwable e) {
//		log.info(StringUtils.buildAlarmMsg(null,null));
        log.error("系统异常====>{}", getExceptionStack(e));
        threadLocal.remove();
        MDC.remove(LogConstants.TRACE_ID);
    }

    private static String getExceptionStack(Throwable throwable) {
        try (StringWriter sw = new StringWriter(); PrintWriter pw = new PrintWriter(sw)) {
            throwable.printStackTrace(pw);
            pw.flush();
            sw.flush();
            return sw.toString();
        } catch (Exception ignored) {
            log.info("获取异常堆栈异常", ignored);
            return "获取堆栈异常";
        }
    }
}
